package top.meeting.room.common.sql;

import com.jfinal.kit.JavaKeyword;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.generator.BaseModelGenerator;
import com.jfinal.plugin.activerecord.generator.ColumnMeta;
import com.jfinal.plugin.activerecord.generator.TableMeta;
import com.xiaoleilu.hutool.util.StrUtil;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

/**
 * 我有故事，你有酒么？
 * JKhaled created by yunqisong@foxmail.com 2017/7/24
 * FOR : 重写的BaseModel生成器
 */
public class JKBaseModelGenerator extends BaseModelGenerator {

    public String packageTemplate =
            "package %s;%n%n";
    public String importTemplate =
            "import com.jfinal.plugin.activerecord.Model;%n" +
                    "import com.jfinal.plugin.activerecord.IBean;%n%n";
    public String classDefineTemplate =
            "/**%n" +
                    " * 我有故事，你有酒么？%n" +
                    " * JKhaled created by yunqisong@foxmail.com  %n" +
                    " * FOR : %s %n" +
                    " */%n" +
                    "@SuppressWarnings(\"serial\")%n" +
                    "public abstract class %s<M extends %s<M>> extends Model<M> implements IBean {%n%n";
    public String classDefineForSetterChainTemplate =
            "/**%n" +
                    " * 我有故事，你有酒么？%n" +
                    " * JKhaled created by yunqisong@foxmail.com  %n" +
                    " * FOR : %s %n" +
                    " */%n" +
                    "@SuppressWarnings({\"serial\", \"unchecked\"})%n" +
                    "public abstract class %s<M extends %s<M>> extends Model<M> implements IBean {%n%n";
    public String setterTemplate =
            "\tpublic void %s(%s %s) {%n" +
                    "\t\tset(\"%s\", %s);%n" +
                    "\t}%n%n";
    public String setterChainTemplate =
            "\tpublic M %s(%s %s) {%n" +
                    "\t\tset(\"%s\", %s);%n" +
                    "\t\treturn (M)this;%n" +
                    "\t}%n%n";

    public String getterTemplate =
            "\tpublic %s %s() {%n" +
                    "\t\treturn get(\"%s\");%n" +
                    "\t}%n%n";
    public String fieldsTemplate = "\tpublic static final String %s = %s ; %n%n";

    public String baseModelPackageName;
    public String baseModelOutputDir;
    public boolean generateChainSetter = false;

    public JavaKeyword javaKeyword = JavaKeyword.me;

    /**
     * 构造器
     *
     * @param baseModelPackageName
     * @param baseModelOutputDir
     */
    public JKBaseModelGenerator(String baseModelPackageName, String baseModelOutputDir) {
        super(baseModelPackageName, baseModelOutputDir);
        if (StrKit.isBlank(baseModelPackageName)) {
            throw new IllegalArgumentException("baseModelPackageName can not be blank.");
        }
        if (baseModelPackageName.contains("/") || baseModelPackageName.contains("\\")) {
            throw new IllegalArgumentException("baseModelPackageName error : " + baseModelPackageName);
        }
        if (StrKit.isBlank(baseModelOutputDir)) {
            throw new IllegalArgumentException("baseModelOutputDir can not be blank.");
        }

        this.baseModelPackageName = baseModelPackageName;
        this.baseModelOutputDir = baseModelOutputDir;
    }

    /**
     * 创建 setter 方法
     *
     * @param generateChainSetter
     */
    public void setGenerateChainSetter(boolean generateChainSetter) {
        this.generateChainSetter = generateChainSetter;
    }

    /**
     * 创建数据
     *
     * @param tableMetas
     */
    public void generate(List<TableMeta> tableMetas) {
        System.out.println("Generate base model ...");
        System.out.println("Base Model Output Dir: " + baseModelOutputDir);
        for (TableMeta tableMeta : tableMetas) {
            genBaseModelContent(tableMeta);
        }
        writeToFile(tableMetas);
    }

    /**
     * 创建 BaseModel的过程
     *
     * @param tableMeta
     */
    public void genBaseModelContent(TableMeta tableMeta) {
        StringBuilder ret = new StringBuilder();
        genPackage(ret);
        genImport(ret);
        genClassDefine(tableMeta, ret);
        for (ColumnMeta columnMeta : tableMeta.columnMetas) {
            genFiled(columnMeta, ret);  // 创建 java属性
        }
        for (ColumnMeta columnMeta : tableMeta.columnMetas) {
            genSetMethodName(columnMeta, ret);
            genGetMethodName(columnMeta, ret);
        }
        ret.append(String.format("}%n"));
        tableMeta.baseModelContent = ret.toString();
    }

    /**
     * 创建 java 属性
     *
     * @param columnMeta
     * @param ret
     */
    public void genFiled(ColumnMeta columnMeta, StringBuilder ret) {
        String filedName = columnMeta.attrName;
//        String argName = javaKeyword.contains(columnMeta.attrName) ? "_" + columnMeta.attrName : columnMeta.attrName;
        String template = fieldsTemplate;
        String filed = String.format(template, filedName, "\"" + StrUtil.toUnderlineCase(filedName) + "\"");
        ret.append(filed);
    }


    public void genPackage(StringBuilder ret) {
        ret.append(String.format(packageTemplate, baseModelPackageName));
    }

    public void genImport(StringBuilder ret) {
        ret.append(String.format(importTemplate));
    }

    public void genClassDefine(TableMeta tableMeta, StringBuilder ret) {
        String template = generateChainSetter ? classDefineForSetterChainTemplate : classDefineTemplate;
        ret.append(String.format(template, tableMeta.baseModelName, tableMeta.baseModelName, tableMeta.baseModelName));
    }

    /**
     * 创建链式setter
     *
     * @param columnMeta
     * @param ret
     */
    public void genSetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
        String setterMethodName = "set" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        // 如果 setter 参数名为 java 语言关键字，则添加下划线前缀 "_"
        String argName = javaKeyword.contains(columnMeta.attrName) ? "_" + columnMeta.attrName : columnMeta.attrName;
        String template = generateChainSetter ? setterChainTemplate : setterTemplate;
        String setter = String.format(template, setterMethodName, columnMeta.javaType, argName, columnMeta.name, argName);
        ret.append(setter);
    }

    public void genGetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
        String getterMethodName = "get" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        String getter = String.format(getterTemplate, columnMeta.javaType, getterMethodName, columnMeta.name);
        ret.append(getter);
    }

    public void writeToFile(List<TableMeta> tableMetas) {
        try {
            for (TableMeta tableMeta : tableMetas) {
                writeToFile(tableMeta);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * base model 覆盖写入
     */
    public void writeToFile(TableMeta tableMeta) throws IOException {
        File dir = new File(baseModelOutputDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        String target = baseModelOutputDir + File.separator + tableMeta.baseModelName + ".java";
        FileWriter fw = new FileWriter(target);
        try {
            fw.write(tableMeta.baseModelContent);
        } finally {
            fw.close();
        }
    }
}







